#ifndef BACKPACK_ITEM_VARIANT_H_
#define BACKPACK_ITEM_VARIANT_H_
#pragma once

#include <boost/variant.hpp>
#include <functional>

namespace backpack {

class Key;
class StoryItem;
class ItemPart;


// all usable item types must be added to ItemVariant
typedef boost::variant<
  std::reference_wrapper<const Key>,
  std::reference_wrapper<const StoryItem>,
  std::reference_wrapper<const ItemPart>
> ItemVariant;



extern const ItemVariant g_itemNull;



template <class Item>
inline bool operator<(
    std::reference_wrapper<Item> const& lhs,
    std::reference_wrapper<Item> const& rhs) {
  return lhs.get() < rhs.get();
}

template <class Item>
inline bool operator==(
    std::reference_wrapper<Item> const& lhs,
    std::reference_wrapper<Item> const& rhs) {
  return lhs.get() == rhs.get();
}

inline bool operator!=(ItemVariant const& lhs, ItemVariant const& rhs) {
  return !(lhs == rhs);
}



template <class Visitor>
class ItemVisitor : public boost::static_visitor<> {
public:
  ItemVisitor(Visitor &&v)
    : m_visitor(std::forward<Visitor>(v)) {
  }
  template <class Item>
  void operator() (std::reference_wrapper<const Item> const& wrapper) const {
    m_visitor(wrapper.get());
  }
  template <class Item>
  void operator() (std::reference_wrapper<const Item> const& wrapper) {
    m_visitor(wrapper.get());
  }

private:
  Visitor m_visitor;
}; // class ItemVisitor



template <class Visitor>
ItemVisitor<Visitor> makeItemVisitor(Visitor &&v) {
  return ItemVisitor<Visitor>(std::forward<Visitor>(v));
}


} // namespace backpack

#endif // BACKPACK_ITEM_VARIANT_H_

